package org.taobao.ibatiside.ui.wizard;

import java.beans.PropertyChangeEvent;
import java.net.URL;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.databinding.beans.BeansObservables;
import org.eclipse.core.databinding.beans.PojoObservables;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.map.IObservableMap;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.runtime.IPath;
import org.eclipse.datatools.modelbase.sql.query.QuerySelectStatement;
import org.eclipse.datatools.sqltools.core.profile.ProfileUtil;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckboxCellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.wb.swt.SWTResourceManager;
import org.taobao.ibatiside.ui.util.JavaClassDialog;
import org.taobao.ibatiside.ui.util.MiscHelper;
import org.taobao.ibatiside.ui.util.WorkspaceUtil;

public class DataObjectGroup extends PageComposite {
	
	private static final String[] PROPERTY_ENABLE = new String[]{"enable"};
	private static final String[] PROPERTY_FIELD_NAME = new String[]{"fieldName"};
	private static final String[] PROPERTY_TYPE = new String[]{"typeName"};
	private Text textDataobjectPath;
	private Table table;
	private Button button;
	private TableViewer tableViewer;
	private Combo combo;
	private ComboViewer doTemplateViewer;
	public DataObjectGroup(Composite parent, int style, BatisCommonPage page) {
		super(parent, style, page);
	}
	@Override
	public void doNotifyChanged(Notification notification) {

	}

	@Override
	protected void doPropertyChange(PropertyChangeEvent evt) {
		String pn = evt.getPropertyName();
		if (BatisSettingModel.K_BEAN_PATH.equals(pn)){
			IPath new_bean_path = (IPath) evt.getNewValue();
			if (new_bean_path != null){
				textDataobjectPath.setText(WorkspaceUtil.getClassPathString(null, new_bean_path));
			}
		}else if(BatisSettingModel.K_BEAN_NEED_CREATE.equals(pn)){
			boolean create_new = ((Boolean)evt.getNewValue());
			if (create_new){
				if (!(model.getDtpStmt() instanceof QuerySelectStatement)){
					MessageDialog.openError(getShell(), "Error", "Wrong sql statement to produce data object");
					model.setBeanNeedCreate(false);
					return;
				}
				try {
					model.setBeanFields(genBeanFields());
				} catch (Exception e) {
					e.printStackTrace();
					setErrorMessage(e.getLocalizedMessage());
				}
			}else{
				model.setBeanFields(Collections.<DataObjectField>emptyList());
			}
		}else if(BatisSettingModel.K_BEAN_FIELDS.equals(pn)){
			tableViewer.setInput(evt.getNewValue());
		}else if (BatisSettingModel.K_DTP_STMT.equals(pn)){
			boolean b_bean_create = evt.getNewValue() == null || evt.getNewValue() instanceof QuerySelectStatement;
			if (!b_bean_create)
				model.setBeanNeedCreate(b_bean_create);
		}
	}

	private List<DataObjectField> genBeanFields() throws Exception{
		Connection conn = ProfileUtil.createConnection(model.getConnectionProfile(), null);
		List<DataObjectField> fields = new ArrayList<DataObjectField>();
		if (conn == null){
			throw new SQLException("Can't establish jdbc connection, please check errorlog view!");
		}
		ResultSet description = null;
		try{
			org.eclipse.datatools.modelbase.sql.tables.Table query_table = ((BatisCommonWizard)hostPage.getWizard()).getDtpFacade().getOperationalTable(model.getDtpStmt());
			if (query_table != null){
				DatabaseMetaData db_meta = conn.getMetaData();
				String schema = query_table.getSchema() != null ? query_table.getSchema().getName() : null;
				String catalog = schema != null && query_table.getSchema().getCatalog() != null ? query_table.getSchema().getCatalog().getName() : null;
				description = db_meta.getTables(catalog, schema, query_table.getName(), null);
				if (description.next()){
					String tb_desc = description.getString("REMARKS");
					if (StringUtils.isNotBlank(tb_desc))
						model.setBeanDescription(tb_desc);
				}
				description.close();
				description = db_meta.getColumns(catalog, schema, query_table.getName(),null);
				while (description.next()){
					DataObjectField f1 = new DataObjectField();
					String cn = description.getString("COLUMN_NAME");
					f1.setColumnName(cn);
					f1.setNativeType(description.getString("TYPE_NAME"));
					int ct = description.getInt("DATA_TYPE");
					f1.setJdbcType(ct);
					f1.setColumnComment(description.getString("REMARKS"));
					f1.setFieldName(MiscHelper.sqlId2JavaId(cn));
					f1.setTypeName(((BatisCommonWizard)hostPage.getWizard()).getDtpFacade().getJavaType(model.getConnectionProfile(), ct));
					fields.add(f1);
				}
				description.close();
			}
		}finally{
			if (description != null && !description.isClosed()){
				description.close();
			}
		}
		return fields;
	}
	@Override
	protected void createContent() {
		setLayout(new GridLayout(1, false));
		Composite composite = new Composite(this, SWT.NONE);
		composite.setLayout(new RowLayout(SWT.HORIZONTAL));
		button = new Button(composite, SWT.CHECK);
		button.setText("Create");
		button.setForeground(SWTResourceManager.getColor(139, 0, 0));
		Label label = new Label(composite, SWT.NONE);
		label.setText(" Class");

		textDataobjectPath = new Text(composite, SWT.BORDER);
		textDataobjectPath.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseDoubleClick(MouseEvent e) {
				JavaClassDialog dialog = new JavaClassDialog(getShell(), model.getCurrentProject());
				if (model.getBeanPath() != null){
					dialog.setResourcePath(model.getBeanPath());
				}else{
					org.eclipse.datatools.modelbase.sql.tables.Table q_table = ((BatisCommonWizard)hostPage.getWizard()).getDtpFacade().getOperationalTable(model.getDtpStmt());
					if (q_table != null){
						dialog.setDefaultName(model.getNamingConversion().getDataObjectName(q_table.getName()));
					}
				}
				if(dialog.open() == JavaClassDialog.OK){
					model.setBeanPath(dialog.getResourcePath());
				}
			}
		});
		textDataobjectPath.setLayoutData(new RowData(299, SWT.DEFAULT));
		
		Label lblTemplate = new Label(composite, SWT.NONE);
		lblTemplate.setText("Template");
		
		doTemplateViewer = new ComboViewer(composite, SWT.NONE);
		combo = doTemplateViewer.getCombo();
		combo.setLayoutData(new RowData(140, SWT.DEFAULT));

		tableViewer = new TableViewer(this, SWT.BORDER
				| SWT.FULL_SELECTION);
		table = tableViewer.getTable();
		table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
		table.setLinesVisible(true);
		table.setHeaderVisible(true);
		tableViewer.setContentProvider(new ArrayContentProvider());
		TableViewerColumn tableViewerColumn = new TableViewerColumn(
				tableViewer, SWT.NONE);
		tableViewerColumn.setLabelProvider(new ColumnLabelProvider() {
			public Image getImage(Object element) {
				return null;
			}
			public String getText(Object element) {
				return element == null ? "" : ((DataObjectField)element).getColumnName();
			}
		});
		TableColumn tableColumn = tableViewerColumn.getColumn();
		tableColumn.setWidth(114);
		tableColumn.setText("Column Name");

		TableViewerColumn tableViewerColumn_1 = new TableViewerColumn(
				tableViewer, SWT.NONE);
		tableViewerColumn_1.setLabelProvider(new ColumnLabelProvider() {
			public Image getImage(Object element) {
				return null;
			}
			public String getText(Object element) {
				return element == null ? "" : ((DataObjectField)element).getNativeType();
			}
		});
		TableColumn tableColumn_1 = tableViewerColumn_1.getColumn();
		tableColumn_1.setWidth(110);
		tableColumn_1.setText("Column Type");

		TableViewerColumn tableViewerColumn_2 = new TableViewerColumn(
				tableViewer, SWT.NONE);
		tableViewerColumn_2.setEditingSupport(new EditingSupport(tableViewer) {
			protected boolean canEdit(Object element) {
				return true;
			}
			protected CellEditor getCellEditor(Object element) {
				return new TextCellEditor(table);
			}
			protected Object getValue(Object element) {
				return ((DataObjectField)element).getFieldName();
			}
			protected void setValue(Object element, Object value) {
				String str = (String) value;
				if (StringUtils.isNotBlank(str)){
				((DataObjectField)element).setFieldName(str);
				tableViewer.update(element, PROPERTY_FIELD_NAME);
				}
			}
		});
		tableViewerColumn_2.setLabelProvider(new ColumnLabelProvider() {
			public Image getImage(Object element) {
				return null;
			}
			public String getText(Object element) {
				return element == null ? "" : ((DataObjectField)element).getFieldName();
			}
		});
		TableColumn tableColumn_2 = tableViewerColumn_2.getColumn();
		tableColumn_2.setWidth(127);
		tableColumn_2.setText("Class Field Name");

		TableViewerColumn tableViewerColumn_3 = new TableViewerColumn(
				tableViewer, SWT.NONE);
		tableViewerColumn_3.setEditingSupport(new EditingSupport(tableViewer) {
			protected boolean canEdit(Object element) {
				return true;
			}
			protected CellEditor getCellEditor(Object element) {
				return new ComboBoxCellEditor(table, MiscHelper.MAPPING_JAVA_TYPE, SWT.READ_ONLY);
			}
			protected Object getValue(Object element) {
				return element != null ? ArrayUtils.indexOf(MiscHelper.MAPPING_JAVA_TYPE, ((DataObjectField)element).getTypeName(),0) : -1;
				
			}
			protected void setValue(Object element, Object value) {
				Integer idx = (Integer) value;
				String selected_type =  0 <= idx && idx < MiscHelper.MAPPING_JAVA_TYPE.length ? MiscHelper.MAPPING_JAVA_TYPE[idx] : null;
				if (selected_type != null){
					((DataObjectField)element).setTypeName(selected_type);
					tableViewer.update(element, PROPERTY_TYPE);
				}
			}
		});
		tableViewerColumn_3.setLabelProvider(new ColumnLabelProvider() {
			public Image getImage(Object element) {
				return null;
			}
			public String getText(Object element) {
				return element == null ? "" : ((DataObjectField)element).getTypeName();
			}
		});
		TableColumn tableColumn_3 = tableViewerColumn_3.getColumn();
		tableColumn_3.setWidth(216);
		tableColumn_3.setText("Class Field Type");

		TableViewerColumn tableViewerColumn_4 = new TableViewerColumn(
				tableViewer, SWT.NONE);
		tableViewerColumn_4.setEditingSupport(new EditingSupport(tableViewer) {
			protected boolean canEdit(Object element) {
				return true;
			}
			protected CellEditor getCellEditor(Object element) {
				return new CheckboxCellEditor(table);
			}
			protected Object getValue(Object element) {
				return ((DataObjectField)element).isEnable();
			}
			protected void setValue(Object element, Object value) {
				((DataObjectField)element).setEnable(((Boolean)value));
				tableViewer.update(element, PROPERTY_ENABLE);
			}
		});
		tableViewerColumn_4.setLabelProvider(new ColumnLabelProvider() {
			public Image getImage(Object element) {
				return null;
			}
			public String getText(Object element) {
				return element == null ? "" : ((DataObjectField)element).isEnable() ? "Y" : "N";
			}
		});
		TableColumn tblclmnCk = tableViewerColumn_4.getColumn();
		tblclmnCk.setWidth(47);
		tblclmnCk.setText("CK");

	}
	protected void doBinding(org.eclipse.emf.databinding.EMFDataBindingContext bindingContext) {
		//
		IObservableValue buttonObserveSelectionObserveWidget = SWTObservables.observeSelection(button);
		IObservableValue modelBeanNeedCreateObserveValue = BeansObservables.observeValue(model, "beanNeedCreate");
		bindingContext.bindValue(buttonObserveSelectionObserveWidget, modelBeanNeedCreateObserveValue, null, null);
		//
		IObservableValue textDataobjectPathObserveEnabledObserveWidget = SWTObservables.observeEnabled(textDataobjectPath);
		bindingContext.bindValue(textDataobjectPathObserveEnabledObserveWidget, buttonObserveSelectionObserveWidget, null, null);
		
		IObservableValue tableObserveEnabledObserveWidget = SWTObservables.observeEnabled(table);
		bindingContext.bindValue(tableObserveEnabledObserveWidget, buttonObserveSelectionObserveWidget, null, null);
		//
		
		ObservableListContentProvider listContentProvider = new ObservableListContentProvider();
		IObservableMap observeMap = PojoObservables.observeMap(listContentProvider.getKnownElements(), URL.class, "file");
		doTemplateViewer.setLabelProvider(new ObservableMapLabelProvider(observeMap){
			@Override
			public String getText(Object element) {
				String fp = super.getText(element);
				Matcher matcher = MiscHelper.DATAOBJECT_PATTERN.matcher(fp);
				return matcher.find() ? matcher.group(1) : fp;
			}
		});
		doTemplateViewer.setContentProvider(listContentProvider);
		//
		IObservableList modelBeanTemplatesObserveList = BeansObservables.observeList(Realm.getDefault(), model, "beanTemplates");
		doTemplateViewer.setInput(modelBeanTemplatesObserveList);
		
		IObservableValue doTemplateViewerObserveSingleSelection = ViewersObservables.observeSingleSelection(doTemplateViewer);
		IObservableValue modelBeanTemplateObserveValue = BeansObservables.observeValue(model, "beanTemplate");
		bindingContext.bindValue(doTemplateViewerObserveSingleSelection, modelBeanTemplateObserveValue, null, null);

		IObservableValue template_ob = SWTObservables.observeEnabled(combo);
		bindingContext.bindValue(template_ob, buttonObserveSelectionObserveWidget);
	}
}
